import axios, { errorCode, cError } from '@/plugins/axios'
import { RESPONSE, REQUEST } from '@/config'
import { confirm, msgError, loading, closeLoading } from '@/plugins/modal'
import { getToken, clearToken } from '@/utils/user'
import cache from '@/plugins/cache'
import router from '@/router'


let downloadLoadingInstance // 下载文件的提示
export let isShowLogin = { show: false } // 是否显示重新登录



/**
 * 发送请求
 * @param {*} config  请求配置
 *                    url,method,data,params,headers是axios的配置
 *                    others            axios的除上面的5种配置外的配置
 *                    isToken           是否带有token 默认带，当为false时不带
 *                    isRepeatSubmit    是否验证重复提交，默认验证，当为false时不验证
 *                    loading           是否显示加载效果，默认不显示，当不为假时显示
 *                    isErrorShow         错误时提示错误，默认提示，当为false时不显示
 *
 */
function baseRequest(config) {
  config = config || {}
  if (typeof config === 'string') config = { url: config }
  const url = config.url || ''
  const method = (config.method || 'post').toLowerCase()
  const data = config.data || {}
  const params = config.params || {}
  let headers = config.headers || {}

  const isToken = config.isToken !== false // 是否需要设置 token
  const isRepeatSubmit = config.isRepeatSubmit !== false // 是否需要防止数据重复提交
  const isErrorShow = config.isErrorShow !== false // 是否显示错误

  // 让每个请求携带自定义token 请根据实际情况自行修改
  if (isToken) headers['Authorization'] = 'Bearer ' + getToken()

  // 防止数据重复提交
  if (isRepeatSubmit && (method === 'post' || method === 'get')) {
    const requestObj = {
      url: config.url,
      data: JSON.stringify(data),
      params: JSON.stringify(params),
      time: new Date().getTime()
    }
    const requestSize = Object.keys(JSON.stringify(requestObj)).length // 请求数据大小
    const limitSize = 1024 * 1024 // 限制存放数据1M
    if (requestSize < limitSize) {
      const sessionObj = cache.session().get('vv__request_repeat', null)
      if (!sessionObj) {
        cache.session().set('vv__request_repeat', requestObj)
      } else {
        const s_url = sessionObj.url // 请求地址
        const s_data = sessionObj.data // 请求数据
        const s_params = sessionObj.params // 请求数据
        const s_time = sessionObj.time // 请求时间
        const interval = REQUEST.REPEAT_TIME // 间隔时间
        if (
          s_url === requestObj.url &&
          s_params === requestObj.params &&
          s_data === requestObj.data &&
          requestObj.time - s_time < interval
        ) {
          const msg = method === 'post' ? '数据正在处理，请勿重复提交' : '请求太过频繁，请稍后再试！'
          isErrorShow && msgError(msg)
          return Promise.reject(cError(msg))
        } else {
          cache.session().set('vv__request_repeat', requestObj)
        }
      }
    }
  }

  // 是否显示加载动画
  const showLoad = config.loading || false
  let loadingObject = null
  if (showLoad) {
    if (showLoad === true) {
      loadingObject = loading()
    } else {
      loadingObject = loading(showLoad)
    }
  }

  let others = config?.others || {}
  let responseType = config?.responseType || others?.responseType || ''
  // 1.7.0以上才支持adapter属性设置fetch，stream流式请求只支持fetch
  if (responseType === 'stream') {
    others.adapter = 'fetch'
  }

  return new Promise((resolve, reject) => {
    axios
      .request({
        url: url,
        method: method,
        params: params,
        data: data,
        headers: headers,
        ...others
      })
      .then(res => {
        // 增加流式输出兼容
        if (responseType === 'stream') {
          res.body = res.data // fetch请求响应值是放在body里面，这里为了不修改调用代码做重新赋值
          return resolve(res)
        }
        const result = res.data || {} //返回结果
        const code = result.code //返回结果code
        const msg = errorCode[code] || result.msg || errorCode['default'] // 获取错误信息

        // 二进制数据则直接返回
        if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
          return result
        }

        //登录失效，清除token
        if (code === RESPONSE.LOGIN_CODE) {
          if (!isShowLogin.show) {
            isShowLogin.show = true
            confirm('登录状态已过期，您可以继续留在该页面，或者重新登录', '系统提示', { confirmButtonText: '重新登录' })
              .then(() => {
                isShowLogin.show = false
                clearToken().then(() => {
                  router.replace({name: 'Login'})
                })
              })
              .catch(() => {
                isShowLogin.show = false
              })
          }
          reject(cError('无效的会话，或者会话已过期，请重新登录。', code))
        } else if (code !== RESPONSE.SUCCESS_CODE) {
          isErrorShow && msgError(msg)
          reject(cError(msg, code))
        } else {
          resolve({ msg: result.msg, ...result.data })
        }
      })
      .catch(err => {
        let message = err.message || '网络请求失败'
        if (message === 'Network Error') {
          message = '后端接口连接异常'
        } else if (message.includes('timeout')) {
          message = '系统接口请求超时'
        } else if (message.includes('Request failed with status code')) {
          message = '系统接口' + message.substr(message.length - 3) + '异常'
        }
        !axios.isCancel(err) && isErrorShow && msgError(message)
        reject(cError(message))
      })
      .finally(() => {
        if (showLoad && loadingObject) closeLoading(loadingObject)
      })
  })
}
let uploadUnique = 0  //防止批量上传时，同一接口和参数 会取消上传请求
export default {
  request: config => baseRequest(config),
  post: (url, data = undefined, config = undefined) => {
    config = config || {}
    config.url = url
    if (data) {
      let cData = config.data || {}
      config.data = { ...data, ...cData }
    }
    return baseRequest({ method: 'post', ...config })
  },
  get: (url, params = undefined, config = undefined) => {
    config = config || {}
    config.url = url
    if (params) {
      let cParams = config.params || {}
      config.params = { ...params, ...cParams }
    }
    return baseRequest({ method: 'get', ...config })
  },
  upload: (url, data = undefined, config = undefined) => {
	uploadUnique++
    config = config || {}
    config.url = url
    config.data = data
    config.params = { _u: uploadUnique }
    config.headers = { 'Content-Type': 'multipart/form-data', ...(config.headers || {}) }
    return baseRequest({ method: 'post', ...config })
  },
  download: (url, data, filename= undefined, config=undefined) => {
    downloadLoadingInstance = loading('正在下载数据，请稍候')
    config = config || {}
    config.url = url
    config.data = config.data || {}
    if (data) config.data = { ...config.data, ...data }
    if (filename) config.filename = filename
    config.isErrorShow = false
    baseRequest({ method: 'post', ...config })
      .then(async data => {
        if (data.url){
          window.open(data.url)
        }else{
          msgError('文件错误')
        }
        downloadLoadingInstance.close()
      })
      .catch(() => {
        msgError('下载文件出现错误，请联系管理员！')
        downloadLoadingInstance.close()
      })

  }
}
